package io.github.echarts.model.adapter;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.github.echarts.model.CategoryManager;
import io.github.echarts.model.ChartModel;
import io.github.echarts.model.SeriesModel;
import io.github.echarts.model.adapter.series.SeriesTypeAdapter;
import io.github.echarts.model.adapter.series.SeriesTypeAdapterRegistry;
import io.github.echarts.model.context.ChartType;
import io.github.echarts.model.context.ChartTypeDetector;
import io.github.echarts.model.context.ConfigurationContext;
import io.github.echarts.model.context.DataFeatureExtractor;
import io.github.echarts.model.coordinate.CoordinateSystem;
import io.github.echarts.model.coordinate.CoordinateSystemType;
import io.github.echarts.model.coordinate.DataRange;
import io.github.echarts.model.series.SeriesDataAnalyzer;
import io.github.echarts.model.series.SeriesDataManager;
import io.github.echarts.option.EChartOption;
import io.github.echarts.option.series.SeriesOption;

/**
 * 系列数据适配器。
 * 该类负责处理系列数据的适配，包括系列数据的创建、处理和统计分析。
 */
public class SeriesAdapter {

    // 系列类型适配器注册表
    private final SeriesTypeAdapterRegistry seriesTypeAdapterRegistry;
    
    /**
     * 构造函数
     */
    public SeriesAdapter() {
        this.seriesTypeAdapterRegistry = SeriesTypeAdapterRegistry.getInstance();
    }

    /**
     * 适配系列数据。
     * <p>
     * 该方法负责从配置选项中提取系列数据，并创建相应的系列模型。
     * 增强了数据驱动能力，包括：
     * 1. 支持多种系列类型和数据格式
     * 2. 处理堆叠系列
     * 3. 分析系列类型分布
     * 4. 设置合适的坐标系
     * 5. 推断系列顺序偏好
     * </p>
     *
     * @param option 包含系列配置的EChartOption
     * @param model 目标ChartModel
     * @param context 配置上下文
     */
    public void adaptSeries(EChartOption option, ChartModel model, ConfigurationContext context) {
        // 创建系列数据管理器
        SeriesDataManager seriesDataManager = new SeriesDataManager();
        
        // 获取主坐标系ID，并设置为默认坐标系
        CoordinateSystem mainCoordinateSystem = model.getMainCoordinateSystem();
        if (mainCoordinateSystem != null) {
            seriesDataManager.setDefaultCoordinateSystemId(mainCoordinateSystem.getId());
        }
        
        // 处理系列配置
        Object seriesObj = option.getSeries();
        if (seriesObj == null) {
            // 如果没有系列数据，创建空的系列数据管理器
            model.setSeriesDataManager(seriesDataManager);
            return;
        }
        
        // 根据系列配置的类型进行适配
        if (seriesObj instanceof List) {
            @SuppressWarnings("unchecked")
            List<SeriesOption> seriesList = (List<SeriesOption>) seriesObj;
            
            // 分析系列类型分布
            analyzeSeriesTypes(seriesList, context);
            
            // 推断系列顺序偏好
            inferSeriesOrderPreference(seriesList, context);
            
            // 使用适配器创建系列模型
            createSeriesModels(seriesList, seriesDataManager, model.getMainCoordinateSystem(), context);
            
        } else if (seriesObj instanceof SeriesOption[]) {
            SeriesOption[] seriesArray = (SeriesOption[]) seriesObj;
            
            // 转换为List进行分析
            List<SeriesOption> seriesList = Arrays.asList(seriesArray);
            
            // 分析系列类型分布
            analyzeSeriesTypes(seriesList, context);
            
            // 推断系列顺序偏好
            inferSeriesOrderPreference(seriesList, context);
            
            // 使用适配器创建系列模型
            createSeriesModels(seriesList, seriesDataManager, model.getMainCoordinateSystem(), context);
        }
        
        // 设置系列数据管理器
        model.setSeriesDataManager(seriesDataManager);
    }
    
    /**
     * 使用适配器创建系列模型
     * 
     * @param seriesList 系列配置列表
     * @param seriesDataManager 系列数据管理器
     * @param mainCoordinateSystem 主坐标系
     * @param context 配置上下文
     */
    private void createSeriesModels(List<SeriesOption> seriesList, SeriesDataManager seriesDataManager, 
                                   CoordinateSystem mainCoordinateSystem, ConfigurationContext context) {
        String defaultCoordinateSystemId = mainCoordinateSystem != null ? 
            mainCoordinateSystem.getId() : "cartesian_1";
        
        for (int i = 0; i < seriesList.size(); i++) {
            SeriesOption seriesOption = seriesList.get(i);
            String seriesType = seriesOption.getType();
            
            // 尝试获取对应类型的适配器
            SeriesTypeAdapter adapter = seriesTypeAdapterRegistry.getAdapter(seriesType);
            
            if (adapter != null) {
                // 如果有适配器，使用适配器创建模型
                io.github.echarts.model.SeriesModel seriesModel = adapter.createModel(
                    seriesOption, defaultCoordinateSystemId, context);
                
                // 设置系列索引
                if (seriesModel != null) {
                    seriesModel.setSeriesIndex(i);
                    seriesDataManager.addSeries(seriesModel);
                    
                    // 应用视觉样式优化
                    adapter.optimizeVisualStyle(seriesModel, context);
                }
            } else {
                // 如果没有找到适配器，使用传统方式
                seriesDataManager.createSeriesFromOptions(Collections.singletonList(seriesOption));
            }
        }
    }
    
    /**
     * 处理数据并创建配置上下文
     * <p>
     * 该方法负责处理系列数据、计算数据统计特性、创建和配置上下文对象，
     * 并为后续的适配和布局计算准备必要的信息。
     * 主要功能包括：
     * 1. 创建配置上下文对象
     * 2. 初始化类别管理器
     * 3. 处理系列数据
     * 4. 计算数据范围
     * 5. 提取数据特征
     * 6. 检测图表类型
     * 7. 添加数据驱动的配置建议
     * </p>
     *
     * @param model 图表模型
     * @param option 配置选项
     * @param context 配置上下文
     */
    public void processSeriesDataAndCreateContext(ChartModel model, EChartOption option, ConfigurationContext context) {
        // 2. 初始化类别管理器
        CategoryManager categoryManager = new CategoryManager();
        initializeCategoryManager(categoryManager, option);
        model.setCategoryManager(categoryManager); // 设置类别管理器到模型
        
        // 3. 处理系列数据
        if (model.getSeriesDataManager() != null) {
            SeriesDataManager seriesManager = model.getSeriesDataManager();
            
            // 处理数据
            seriesManager.processData();
            
            // 4. 计算数据范围
            seriesManager.calculateDataRanges();
            
            // 确保坐标系的轴模型得到正确的数据范围
            syncCoordinateSystemsWithData(model);
            
            // 5. 提取数据特征
            extractDataFeatures(model, context, option);
            
            // 6. 使用SeriesDataAnalyzer进行高级统计分析
            SeriesDataAnalyzer.analyzeSeriesData(seriesManager, context);
            
            // 7. 检测图表类型
            ChartType chartType = ChartTypeDetector.detectChartType(option, context);
            
            // 8. 添加数据驱动的配置建议
            addDataDrivenConfigurationSuggestions(context, option, chartType);
        }
    }
    
    /**
     * 获取对象的长度(如果是数组或集合)
     * 
     * @param obj 要检查的对象
     * @return 长度，如果不是数组或集合则返回0
     */
    private int getObjectLength(Object obj) {
        if (obj == null) {
            return 0;
        }
        
        if (obj.getClass().isArray()) {
            return Array.getLength(obj);
        }
        
        if (obj instanceof List) {
            return ((List<?>) obj).size();
        }
        
        return 0;
    }
    
    /**
     * 将Object安全地转换为Object[]数组
     * 
     * @param data 可能是数组的对象
     * @return 转换后的Object[]数组，如果无法转换则返回空数组
     */
    private Object[] toObjectArray(Object data) {
        if (data == null) {
            return new Object[0];
        }
        
        // 如果已经是Object[]，直接返回
        if (data instanceof Object[]) {
            return (Object[]) data;
        }
        
        // 如果是其他类型的数组，转换为Object[]
        if (data.getClass().isArray()) {
            int length = Array.getLength(data);
            Object[] result = new Object[length];
            for (int i = 0; i < length; i++) {
                result[i] = Array.get(data, i);
            }
            return result;
        }
        
        // 如果是列表，转换为Object[]
        if (data instanceof List) {
            List<?> list = (List<?>) data;
            return list.toArray(new Object[0]);
        }
        
        // 将单个对象包装为数组
        return new Object[] { data };
    }
    
    /**
     * 初始化类别管理器
     * 
     * @param categoryManager 类别管理器
     * @param option 配置选项
     */
    private void initializeCategoryManager(CategoryManager categoryManager, EChartOption option) {
        // 从数据源中提取类别数据
        if (option.getXAxis() != null && option.getXAxis().getData() != null) {
            // 安全转换为Object[]
            Object[] categories = toObjectArray(option.getXAxis().getData());
            
            // 将类别数据添加到类别管理器
            List<Object> categoryList = new ArrayList<>();
            for (Object category : categories) {
                if (category != null) {
                    categoryList.add(category.toString());
                }
            }
            
            // 添加类别到默认的x轴(使用"x"作为axisId)
            if (!categoryList.isEmpty()) {
                categoryManager.addCategories("x", categoryList);
            }
        }
    }
    
    /**
     * 同步坐标系与数据范围
     * 确保坐标系的轴模型获得正确的数据范围
     * 
     * @param model 图表模型
     */
    private void syncCoordinateSystemsWithData(ChartModel model) {
        SeriesDataManager seriesManager = model.getSeriesDataManager();
        if (seriesManager == null) {
            return;
        }
        
        // 获取所有坐标系
        for (CoordinateSystem cs : model.getCoordinateSystems()) {
            // 对于笛卡尔坐标系，更新Y轴的数据范围
            if (cs instanceof io.github.echarts.model.coordinate.cartesian.CartesianCoordinateSystem) {
                io.github.echarts.model.coordinate.cartesian.CartesianCoordinateSystem cartesian = 
                    (io.github.echarts.model.coordinate.cartesian.CartesianCoordinateSystem) cs;
                
                // 获取该坐标系对应的数据范围
                String csId = cs.getId();
                DataRange range = seriesManager.getDataRange(csId);
                
                // 如果找到了数据范围，设置到坐标系
                if (range != null) {
                    // 如果是DefaultCartesianCoordinateSystem，使用其专用方法
                    if (cs instanceof io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem) {
                        io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem defaultCS = 
                            (io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem) cs;
                        defaultCS.setDataRange(range);
                    }
                    
                    // 确保Y轴有合理的数据范围
                    double min = range.getMin();
                    double max = range.getMax();
                    
                    // 如果数据都是正数，从0开始显示
                    if (min > 0) {
                        min = 0;
                    }
                    
                    // 如果数据都是负数，到0结束显示
                    if (max < 0) {
                        max = 0;
                    }
                    
                    // 如果最大值和最小值相等，扩展范围避免单一值
                    if (Math.abs(max - min) < 0.000001) {
                        if (max == 0) {
                            max = 100;
                        } else {
                            double delta = Math.abs(max) * 0.1;
                            min = min - delta;
                            max = max + delta;
                        }
                    }
                    
                    // 设置数据范围到坐标轴
                    // 使用DefaultCartesianCoordinateSystem中的updateDataRange方法
                    if (cs instanceof io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem) {
                        io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem defaultCS = 
                            (io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem) cs;
                        defaultCS.updateDataRange(min, max);
                    }
                }
            }
        }
    }
    
    /**
     * 从模型中提取数据特征
     *
     * @param model 图表模型
     * @param context 配置上下文
     * @param option 配置选项
     */
    private void extractDataFeatures(ChartModel model, ConfigurationContext context, EChartOption option) {
        SeriesDataManager seriesManager = model.getSeriesDataManager();
        if (seriesManager == null) {
            return;
        }
        
        // 从option中提取数据用于特征分析
        if (option.getSeries() != null) {
            Object seriesObj = option.getSeries();
            
            if (seriesObj instanceof List) {
                @SuppressWarnings("unchecked")
                List<SeriesOption> seriesList = (List<SeriesOption>) seriesObj;
                if (!seriesList.isEmpty() && seriesList.get(0).getData() != null) {
                    // 安全转换为Object[]
                    Object[] data = toObjectArray(seriesList.get(0).getData());
                    
                    // 处理数值数据
                    if (data.length > 0 && data[0] instanceof Number) {
                        Number[] values = new Number[data.length];
                        for (int i = 0; i < data.length; i++) {
                            values[i] = (Number) data[i];
                        }
                        DataFeatureExtractor.extractFeatures(values, context);
                    }
                }
            } else if (seriesObj instanceof SeriesOption[]) {
                SeriesOption[] seriesArray = (SeriesOption[]) seriesObj;
                if (seriesArray.length > 0 && seriesArray[0].getData() != null) {
                    // 安全转换为Object[]
                    Object[] data = toObjectArray(seriesArray[0].getData());
                    
                    // 处理数值数据
                    if (data.length > 0 && data[0] instanceof Number) {
                        Number[] values = new Number[data.length];
                        for (int i = 0; i < data.length; i++) {
                            values[i] = (Number) data[i];
                        }
                        DataFeatureExtractor.extractFeatures(values, context);
                    }
                }
            }
        }
        
        // 从类别轴提取类别数据
        if (option.getXAxis() != null && option.getXAxis().getData() != null) {
            // 安全转换为Object[]
            Object[] data = toObjectArray(option.getXAxis().getData());
            
            if (data.length > 0 && data[0] instanceof String) {
                String[] categories = new String[data.length];
                for (int i = 0; i < data.length; i++) {
                    categories[i] = (String) data[i];
                }
                DataFeatureExtractor.extractCategoryFeatures(categories, context);
            }
        }
    }
    
    /**
     * 添加数据驱动的配置建议
     * 
     * @param context 配置上下文
     * @param option 配置选项
     * @param chartType 图表类型
     */
    private void addDataDrivenConfigurationSuggestions(ConfigurationContext context, EChartOption option, ChartType chartType) {
        ConfigurationContext.DataStatistics stats = context.getDataStatistics();
        
        // 针对数据特性的建议
        if (stats.isHasSingleValue()) {
            // 单一值数据的处理建议
            context.addInfo("singleValueHandling", "extendRange");
        }
        
        if (stats.isHasNegativeValues()) {
            // 负值数据的处理建议
            context.addInfo("negativeValuesHandling", "includeZero");
        }
        
        // 数据密度对布局的影响
        int dataPointCount = stats.getDataPointCount();
        if (dataPointCount > 100) {
            // 大量数据点时的布局建议
            context.addInfo("layoutDensity", "compact");
            context.addInfo("labelStrategy", "sampling");
        } else if (dataPointCount < 5) {
            // 少量数据点时的布局建议
            context.addInfo("layoutDensity", "spacious");
            context.addInfo("labelStrategy", "showAll");
        }
        
        // 数据范围对坐标轴的影响
        double dataRange = stats.getMax() - stats.getMin();
        double absMax = Math.abs(stats.getMax());
        
        if (dataRange < absMax * 0.1) {
            // 数据范围相对较小，可能需要缩放
            context.addInfo("axisSuggestion", "zoomToData");
        }
        
        // 类别数量对布局的影响
        int categoryCount = stats.getCategoryCount();
        if (categoryCount > 10) {
            // 类别较多的处理建议
            context.addInfo("categoryHandling", "rotate");
        }
        
        // 根据高级统计分析结果添加更多配置建议
        addAdvancedConfigurationSuggestions(context);
    }
    
    /**
     * 根据高级统计分析结果添加配置建议
     * 
     * @param context 配置上下文
     */
    private void addAdvancedConfigurationSuggestions(ConfigurationContext context) {
        // 获取分析结果
        Object outlierStatsObj = context.getInfo("outlierStats");
        Object trendStatsObj = context.getInfo("trendStats");
        Object densityStatsObj = context.getInfo("densityStats");
        
        // 处理异常值
        if (outlierStatsObj instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> outlierStats = (Map<String, Object>) outlierStatsObj;
            if (Boolean.TRUE.equals(outlierStats.get("hasOutliers"))) {
                // 存在异常值时的建议
                context.addInfo("outlierHandling", "markPoint");
                context.addInfo("axisScale", "robust");
            }
        }
        
        // 处理数据趋势
        if (trendStatsObj instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> trendStats = (Map<String, Object>) trendStatsObj;
            if (trendStats.containsValue("increasing") || trendStats.containsValue("decreasing")) {
                // 明显趋势时的建议
                context.addInfo("trendVisualization", "showTrendLine");
            }
        }
        
        // 处理数据密度
        if (densityStatsObj instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> densityStats = (Map<String, Object>) densityStatsObj;
            if (Boolean.TRUE.equals(densityStats.get("isHighDensity"))) {
                // 高密度数据的建议
                context.addInfo("dataZoom", "enable");
                context.addInfo("labelOverlap", "avoidance");
            }
        }
    }
    
    /**
     * 分析系列类型分布
     * 
     * @param seriesList 系列列表
     * @param context 配置上下文
     */
    private void analyzeSeriesTypes(List<SeriesOption> seriesList, ConfigurationContext context) {
        if (seriesList == null || seriesList.isEmpty()) {
            return;
        }
        
        // 统计各类型系列数量
        Map<String, Integer> typeCount = new HashMap<>();
        
        // 检查是否存在堆叠系列
        boolean hasStackedSeries = false;
        
        // 记录所有系列类型
        List<String> seriesTypes = new ArrayList<>();
        
        for (SeriesOption series : seriesList) {
            String type = series.getType();
            if (type != null) {
                // 计数类型
                typeCount.put(type, typeCount.getOrDefault(type, 0) + 1);
                
                // 添加到系列类型列表
                if (!seriesTypes.contains(type)) {
                    seriesTypes.add(type);
                }
                
                // 检查堆叠配置
                if (series.getStack() != null && !series.getStack().isEmpty()) {
                    hasStackedSeries = true;
                }
            }
        }
        
        // 存储系列类型信息到上下文
        context.addInfo("seriesTypes", seriesTypes);
        context.addInfo("seriesTypeCount", typeCount);
        context.addInfo("primarySeriesType", seriesTypes.isEmpty() ? null : seriesTypes.get(0));
        context.addInfo("hasStackedSeries", hasStackedSeries);
        context.addInfo("totalSeriesCount", seriesList.size());
        
        // 确定图表类型
        if (seriesTypes.size() == 1) {
            // 单一系列类型
            String type = seriesTypes.get(0);
            context.setChartType(ChartType.fromSeriesType(type));
        } else if (seriesTypes.size() > 1) {
            // 多系列类型
            context.setChartType(ChartType.MIXED);
        }
    }
    
    /**
     * 推断系列顺序偏好
     * 
     * @param seriesList 系列列表
     * @param context 配置上下文
     */
    private void inferSeriesOrderPreference(List<SeriesOption> seriesList, ConfigurationContext context) {
        if (seriesList == null || seriesList.isEmpty()) {
            return;
        }
        
        // 根据系列类型推断绘制顺序偏好
        // 例如：面积图应该先绘制，然后是柱状图，最后是线图
        Map<String, Integer> drawingOrderPreference = new HashMap<>();
        drawingOrderPreference.put("bar", 20);  // 柱状图中等优先级
        drawingOrderPreference.put("line", 30); // 线图高优先级
        drawingOrderPreference.put("scatter", 40); // 散点图更高优先级
        drawingOrderPreference.put("pie", 10);  // 饼图低优先级
        drawingOrderPreference.put("area", 5);  // 面积图最低优先级
        drawingOrderPreference.put("radar", 25); // 雷达图中高优先级
        
        // 存储推断的顺序偏好
        context.addInfo("seriesOrderPreference", drawingOrderPreference);
    }
    
    /**
     * 为每个系列关联对应的坐标系实例
     * 
     * @param model 图表模型
     */
    public void linkSeriesToCoordinateSystems(ChartModel model) {
        SeriesDataManager seriesManager = model.getSeriesDataManager();
        if (seriesManager == null) {
            return;
        }
        
        for (io.github.echarts.model.SeriesModel series : seriesManager.getSeriesModels()) {
            // 获取系列指定的坐标系ID
            String csId = series.getCoordinateSystemId();
            
            // 获取对应的坐标系实例
            CoordinateSystem cs = model.getCoordinateSystemById(csId);
            
            // 设置坐标系到系列
            if (cs != null) {
                series.setCoordinateSystem(cs);
            }
        }
    }
} 